package com.gzhryc.shared_device.cdcz.code.services;

import com.gzhryc.common.StringTools;
import com.gzhryc.common.exceptions.LogicException;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.jdbc.Conditions;
import com.gzhryc.jdbc.JdbcSession;
import com.gzhryc.jdbc.MultiDBTools;
import com.gzhryc.shared_device.base.IDeviceService;
import com.gzhryc.shared_device.cdcz.code.CDCZProduceConfig;
import com.gzhryc.shared_device.cdcz.code.dao.ChargeSocketDao;
import com.gzhryc.shared_device.cdcz.code.dao.db.ChargeSocket;
import com.gzhryc.shared_device.cdcz.code.dao.db.ChargeSocketSlot;
import com.gzhryc.shared_device.cdcz.code.dao.enums.ChargeSocketEnum;
import com.gzhryc.shared_device.cdcz.code.dao.enums.ChargeSocketSlotEnum;
import com.gzhryc.shared_device.cdcz.code.services.dto.ChargeSocketSearch;
import com.gzhryc.shared_device.common.device.dao.db.Device;
import com.gzhryc.shared_device.common.device.dao.db.DeviceProduceBatch;
import com.gzhryc.shared_device.common.device.dao.db.DeviceTypeFunc;
import com.gzhryc.shared_device.common.device.services.DeviceService;
import com.gzhryc.shared_device.common.device.services.dto.DeviceSearch;
import com.gzhryc.shared_device.iot.code.dao.db.IOTServerNode;
import com.gzhryc.shared_device.iot.code.services.IOTServerNodeService;

import java.sql.SQLException;
import java.util.*;

public class ChargeSocketService implements IDeviceService {

    static Logger log = Logger.getLogger(ChargeSocketService.class);

    public static ChargeSocketService self() {
        return MultiDBTools.getService(ChargeSocketService.class, true);
    }

    public static ChargeSocketService self(String jdbcKey) {
        return MultiDBTools.getService(jdbcKey, ChargeSocketService.class, true);
    }

    ChargeSocketDao dao;

    public ChargeSocketService(String jdbcKey) {
        dao = new ChargeSocketDao(jdbcKey);
    }
    
    public List<ChargeSocket> findJoinBySearch(ChargeSocketSearch search) {
        Conditions conditions = dao.buildConditions(search);
        conditions.and().in("deviceSn",search.getDeviceSnList());
        conditions.and().is("device.user_id",search.getUserId());
        conditions.and().is("device.place_id",search.getPlaceId());
        conditions.and().likeBoth("deviceSn",search.getTrim()).or().likeBoth("device.place_name",search.getTrim());
        if(search.getDeploy() != null){
            if(search.getDeploy()){
                conditions.and().isNotNull("device.place_id");
            }else{
                conditions.and().isNull("device.place_id");
            }
        }
        try {
            return dao.findJoinByCondition(conditions);
        } catch (SQLException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    public List<ChargeSocket> findJoinBySearch(ChargeSocketSearch search, Integer pageNo, Integer pageLimit) {
        Conditions conditions = dao.buildConditions(search);
        conditions.and().in("deviceSn",search.getDeviceSnList());
        conditions.and().is("device.user_id",search.getUserId());
        conditions.and().is("device.place_id",search.getPlaceId());
        conditions.and().likeBoth("deviceSn",search.getTrim()).or().likeBoth("device.place_name",search.getTrim());
        if(search.getDeploy() != null){
            if(search.getDeploy()){
                conditions.and().isNotNull("device.place_id");
            }else{
                conditions.and().isNull("device.place_id");
            }
        }
        try {
            return dao.findJoinByCondition(conditions, pageNo, pageLimit);
        } catch (SQLException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    public Long countJoinBySearch(ChargeSocketSearch search) {
        Conditions conditions = dao.buildConditions(search);
        conditions.and().in("deviceSn",search.getDeviceSnList());
        conditions.and().is("device.user_id",search.getUserId());
        conditions.and().is("device.place_id",search.getPlaceId());
        conditions.and().likeBoth("deviceSn",search.getTrim()).or().likeBoth("device.place_name",search.getTrim());
        if(search.getDeploy() != null){
            if(search.getDeploy()){
                conditions.and().isNotNull("device.place_id");
            }else{
                conditions.and().isNull("device.place_id");
            }
        }
        try {
            return dao.countJoin(conditions);
        } catch (SQLException e) {
            log.error(e.getMessage(), e);
        }
        return 0L;
    }
    
    public List<ChargeSocket> findByDeviceSnList(List<String> deviceSnList) {
		if (deviceSnList != null && deviceSnList.size() > 0) {
			Conditions conditions = new Conditions(ChargeSocket.class);
			conditions.and().in("deviceSn", deviceSnList);
			try {
				return dao.findByCondition(conditions);
			} catch (SQLException e) {
				log.error(e.getMessage(), e);
			}
		}
		return null;
	}

    public ChargeSocket getByDeviceSn(String deviceSn) {
        if (StringTools.isNotBlank(deviceSn)) {
            Conditions conditions = new Conditions(ChargeSocket.class);
            conditions.and().is("deviceSn", deviceSn);
            try {
                return dao.get(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return null;
    }

    public ChargeSocket getJoinByDeviceSn(String deviceSn) {
        if (StringTools.isNotBlank(deviceSn)) {
            Conditions conditions = new Conditions(ChargeSocket.class);
            conditions.and().is("deviceSn", deviceSn);
            try {
                return dao.getJoin(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return null;
    }

    public boolean add(ChargeSocket chargeSocket) throws LogicException {
        if (chargeSocket.getSlotTotal() == null) {
            throw new LogicException("插座数量不可以为空");
        }
        if (chargeSocket.getIotNodeId() == null) {
            throw new LogicException("IOT节点不可以为空");
        }
        if (StringTools.isBlank(chargeSocket.getProtocolType())) {
            throw new LogicException("设备协议不可以为空");
        }

        IOTServerNode serverNode = IOTServerNodeService.self().getById(chargeSocket.getIotNodeId());
        if(!serverNode.getProtocolType().equals(chargeSocket.getProtocolType())){
            throw new LogicException("设备类型与IOT节点通信协议不一致");
        }

        Device device = DeviceService.self().getByDeviceSn(chargeSocket.getDeviceSn());
        if (device != null) {
            throw new LogicException("设备索引已存在");
        }

        chargeSocket.setCreateDate(new Date());
        JdbcSession.begin();
        try {
            if (dao.insert(chargeSocket) > 0) {
                if (ChargeSocketSlotService.self().addEmptySlot(chargeSocket.getDeviceSn(), chargeSocket.getSlotTotal())) {
                    device = new Device();
                    device.setDeviceSn(chargeSocket.getDeviceSn());
                    device.setDeviceTypeId(chargeSocket.getDeviceTypeId());
                    device.setDeviceTypeName(chargeSocket.getDeviceTypeName());
                    if (DeviceService.self().add(device)) {
                        JdbcSession.commit();
                        return true;
                    }
                }
            }
        } catch (SQLException e) {
            log.error(e.getMessage(), e);
        } finally {
            JdbcSession.end();
        }
        return false;
    }

    public boolean produceDevice(DeviceProduceBatch produceBatch, DeviceTypeFunc deviceTypeFunc,CDCZProduceConfig produceConfig){
        Integer iotType = Integer.valueOf(produceConfig.getIotType());
        Long iotNodeId = Long.valueOf(produceConfig.getIotNodeId());
        DeviceSearch search = new DeviceSearch();
        search.setBatchId(produceBatch.getBatchId());
        Integer pageNo = 1;
        Integer pageLimit = 300;
        List<Device> deviceList = DeviceService.self().findBySearch(search,pageNo,pageLimit);
        List<ChargeSocket> data = new ArrayList<>();
        List<ChargeSocketSlot> slotData = new ArrayList<>();
        while (deviceList != null && deviceList.size() > 0){
            for(Device device : deviceList) {
                ChargeSocket chargeSocket = new ChargeSocket();
                chargeSocket.setDeviceSn(device.getDeviceSn());
                chargeSocket.setDeviceTypeId(device.getDeviceTypeId());
                chargeSocket.setDeviceTypeName(device.getDeviceTypeName());
                chargeSocket.setSlotTotal(deviceTypeFunc.getSlotTotal());
                chargeSocket.setIotType(iotType);
                chargeSocket.setIotNodeId(iotNodeId);
                chargeSocket.setProtocolType(deviceTypeFunc.getProtocolType());
                chargeSocket.setCreateDate(new Date());
                data.add(chargeSocket);

                //卡槽
                for (int i = 1; i <= chargeSocket.getSlotTotal(); i++) {
                    ChargeSocketSlot slot = new ChargeSocketSlot();
                    slot.setDeviceSn(chargeSocket.getDeviceSn());
                    slot.setSlotNum(i);
                    slot.setState(ChargeSocketSlotEnum.State.Free.index());
                    slot.setCreateDate(new Date());
                    slotData.add(slot);
                }
            }
            pageNo = pageNo + 1;
            deviceList = DeviceService.self().findBySearch(search,pageNo,pageLimit);
        }

        JdbcSession.begin();
        try {
            if(dao.insert(data) > 0){
                if(ChargeSocketSlotService.self().add(slotData)){
                    JdbcSession.commit();
                    return true;
                }
            }
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        } finally {
            JdbcSession.end();
        }
        return false;
    }

    public boolean updateDeviceTypeName(String deviceTypeId,String deviceTypeName){
        if(StringTools.isNotBlank(deviceTypeId) && StringTools.isNotBlank(deviceTypeName)){
            Conditions conditions = new Conditions(ChargeSocket.class);
            conditions.and().is("deviceTypeId",deviceTypeId);

            ChargeSocket updateEntity = new ChargeSocket();
            updateEntity.setDeviceTypeName(deviceTypeName);

            try {
                return dao.updateNotNull(updateEntity,conditions) >= 0;
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return false;
    }

    public boolean updateNotNull(ChargeSocket chargeSocket,ChargeSocket updateEntity) throws LogicException {
        updateEntity.setDeviceSn(chargeSocket.getDeviceSn());
        JdbcSession.begin();
        try {
            if(dao.updateNotNull(updateEntity) > 0){
                boolean flag = true;
                if(updateEntity.getSlotTotal() != null && !chargeSocket.getSlotTotal().equals(updateEntity.getSlotTotal())){
                    if(!ChargeSocketSlotService.self().checkSlotTotal(updateEntity)){
                        flag = false;
                    }
                }

                if(flag){
                    JdbcSession.commit();
                    return true;
                }
            }
        } catch (SQLException e) {
            log.error(e.getMessage(), e);
        } finally {
            JdbcSession.end();
        }
        return false;
    }

    public boolean online(ChargeSocket chargeSocket,String version,String iccid, Integer rssi) {
        if (chargeSocket != null && StringTools.isNotBlank(chargeSocket.getDeviceSn())) {
            ChargeSocket updateEntity = new ChargeSocket();
            updateEntity.setDeviceSn(chargeSocket.getDeviceSn());

            boolean flag = false;
            if(StringTools.isBlank(chargeSocket.getVersionNumber()) || !chargeSocket.getVersionNumber().equals(version)){
                flag = true;
                updateEntity.setVersionNumber(version);
            }
            if(StringTools.isBlank(chargeSocket.getIccid()) || !chargeSocket.getIccid().equals(iccid)){
                flag = true;
                updateEntity.setIccid(iccid);
            }
            if(chargeSocket.getRssi() == null|| !chargeSocket.getRssi().equals(rssi)){
                flag = true;
                updateEntity.setRssi(rssi);
            }
            if(!ChargeSocketEnum.State.Online.index().equals(chargeSocket.getState())){
                flag = true;
                updateEntity.setState(ChargeSocketEnum.State.Online.index());
            }

            if(flag){
                try {
                    if(dao.updateNotNull(updateEntity) > 0) {
                        return true;
                    }
                } catch (SQLException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
        return false;
    }

    public boolean offline(String deviceSn) {
        if (StringTools.isNotBlank(deviceSn)) {
            ChargeSocket chargeSocket = new ChargeSocket();
            chargeSocket.setDeviceSn(deviceSn);
            chargeSocket.setState(ChargeSocketEnum.State.Offline.index());
            chargeSocket.setLastOfflineDate(new Date());

            try {
                if(dao.updateNotNull(chargeSocket) > 0){
                    return true;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean heartbeat(ChargeSocket chargeSocket, Integer rssi, Double mcuTemperature) {
        if (chargeSocket != null && StringTools.isNotBlank(chargeSocket.getDeviceSn())) {
            ChargeSocket updateEntity = new ChargeSocket();
            updateEntity.setDeviceSn(chargeSocket.getDeviceSn());

            boolean flag = false;
            if(rssi != null && chargeSocket.getRssi() == null|| !chargeSocket.getRssi().equals(rssi)){
                flag = true;
                updateEntity.setRssi(rssi);
            }
            if(mcuTemperature != null && chargeSocket.getMcuTemperature() == null
                    || !chargeSocket.getMcuTemperature().equals(mcuTemperature)){
                flag = true;
                updateEntity.setMcuTemperature(mcuTemperature);
            }
            if(!ChargeSocketEnum.State.Online.index().equals(chargeSocket.getState())){
                flag = true;
                updateEntity.setState(ChargeSocketEnum.State.Online.index());
            }

            if(flag) {
                try {
                    if(dao.updateNotNull(updateEntity) > 0) {
                        return true;
                    }
                } catch (SQLException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
        return false;
    }

    /**
     * 全部设备离线，只在Leader程序启动时
     */
    public void offlineAll() {
        Conditions conditions = new Conditions(ChargeSocket.class);
        conditions.and().is("state", ChargeSocketEnum.State.Online.index());

        ChargeSocket chargeSocket = new ChargeSocket();
        chargeSocket.setState(ChargeSocketEnum.State.Offline.index());
        try {
            dao.updateNotNull(chargeSocket, conditions);
        } catch (SQLException e) {
            log.error(e.getMessage(), e);
        }
    }

    public boolean deleteByDeviceSn(String deviceSn) throws LogicException {
        if (StringTools.isNotBlank(deviceSn)) {
            Conditions condition = new Conditions(ChargeSocket.class);
            condition.and().is("deviceSn", deviceSn);

            JdbcSession.begin();
            try {
                if (dao.deleteByCondition(condition) > 0) {
                    if (ChargeSocketSlotService.self().deleteByDeviceSn(deviceSn)) {
                        JdbcSession.commit();
                        return true;
                    }
                }else{
                    ChargeSocket chargeSocket = getByDeviceSn(deviceSn);
                    if(chargeSocket == null) {
                        log.info("{{0}}共享插座已删除", deviceSn);
                        if (ChargeSocketSlotService.self().deleteByDeviceSn(deviceSn)) {    //执行一次删除避免脏数据
                            JdbcSession.commit();
                            return true;
                        }
                    }
                }
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            } finally {
                JdbcSession.end();
            }
        }
        return false;
    }
}
